
/** 帧 */
export class Frame<M = any> {

  /** 帧索引 */
  index: number;

  /** 帧数据 */
  info?: M;

  /** 是否关键帧 */
  isKeyframe = false;

  /** 上一个关键帧 */
  previous: Frame<M>;

  /** 下一个关键帧 */
  next: Frame<M>;

  constructor(index: number, info?: M) {
    this.index = index;
    this.info = info;
    this.previous = this;
    this.next = this;
  }
}

// 时间轴对象
export default class TimeLine<M = any> {

  /** 指针 */
  pointer = 0;

  /** 关帧帧字典 */
  private keyframeDictionary = new Map<number, Frame<M>>();

  /** 关键帧列表 */
  readonly keyframeList: Frame<M>[] = [];

  /** 补件帧字典 */
  private tweenFrameDictionary = new Map<number, Frame<M>>();

  /** 补间函数 */
  private tweenFn: (frame: Frame<M>) => M;

  /**
   * 时间轴-构造函数
   * @param tweenFn 补间函数
   * @param keyframe 
   */
  constructor(tweenFn: (frame: Frame<M>) => M, keyframe: Array<[number, M]> = []) {
    this.tweenFn = tweenFn;
    keyframe.forEach(e => { this.setKeyframe(new Frame(e[0], e[1])); });
  }

  /** 
   * 设置关键帧 
   * @param frame 帧数据
   * */
  setKeyframe = (frame: Frame<M>) => {
    frame.isKeyframe = true;

    // 如果没用0关键帧 自动补齐
    (() => {
      if (this.keyframeDictionary.has(0) === false && frame.index !== 0) {
        const frame0 = new Frame(0, frame.info);
        frame0.isKeyframe = true;
        this.keyframeDictionary.set(0, frame);
        this.keyframeList.push(frame);
      }
    })()

    // 添加关键帧
    this.keyframeDictionary.set(frame.index, frame);
    this.keyframeList.push(frame);

    // 不是第一帧 准备补件帧  
    if (frame.index > 0) {
      const tweenList: Frame<M>[] = [];
      for (let i = frame.index - 1; ; i--) {
        const previous = this.keyframeDictionary.get(i);
        if (previous) {
          tweenList.forEach(e => { e.previous = previous });
          return;
        } else {
          const tweenFrame = new Frame<M>(i);
          tweenFrame.next = frame;
          tweenList.push(tweenFrame);
          this.tweenFrameDictionary.set(tweenFrame.index, tweenFrame);
        }
      }
    }
  }

  /** 
   * 设置补件函数 
   * @param index 当前帧索引
   * @param previous 当前帧的上一帧
   * @param next 当前帧的下一帧
   * */
  setTweenFn = (fn: (frame: Frame<M>) => M) => {
    this.tweenFn = fn;
  }

  /** 获取指定帧的数据 */
  getFrameInfo = (index: number) => {
    let frame = this.keyframeDictionary.get(index);
    if (frame) {
      return frame.info;
    } else {
      frame = this.tweenFrameDictionary.get(index);
      if (frame && this.tweenFn) {
        return this.tweenFn(frame)
      }
    }
    return undefined
  }
}
